﻿#include "experimentinfo.h"

extern QMap<QString,TcpClient*> clientList;
extern QMap<QString,SerialportClient*> serialPortClientList;

/**
 * @brief 构造函数
 */
ExperimentInfo::ExperimentInfo()
{
    logClient->getInstance();
}

/**
 * @brief 析构函数
 */
ExperimentInfo::~ExperimentInfo()
{}

Q_INVOKABLE void ExperimentInfo::startExperiment(QVariantMap expInfo,QVariantList sampleInfo,QString type)
{

    if(expInfo.contains("EquId") && expInfo.contains("ExperimentName") && expInfo.contains("AmplGuid")){
        LogHelperJ::write("StartExperiment -"
                          " EquId:" + expInfo["EquId"].toString() +
                " ExperimentName:" + expInfo["ExperimentName"].toString() +
                " AmplId:" + expInfo["AmplGuid"].toString() +
                " >>>");
    }else{
        LogHelperJ::write("StartExperiment Failed - Wrong expInfo");
        QMLSignal::I().emitStartExperimentStatus("0");
        return;
    }

    if(type=="0")//启动实验
    {
        QString experimentGuid=saveExperimentInfo(expInfo);
        saveSampleInfo(sampleInfo,experimentGuid);
        int wlkStatus=  saveWlkFile(experimentGuid,expInfo["ExperimentName"].toString());
        if(wlkStatus==1){
            QMLSignal::I().emitStartExperimentStatus("2");
            return;
        }
        distributeData(experimentGuid,expInfo["EquId"].toString());
    }
    else//只保存wlk文件
    {
        QString experimentGuid=saveExperimentInfo(expInfo);
        saveSampleInfo(sampleInfo,experimentGuid);
        int wlkStatus=  saveWlkFile(experimentGuid,expInfo["ExperimentName"].toString());
        if(wlkStatus==1){
            QMLSignal::I().emitStartExperimentStatus("2");
            return;
        }
        WlkOperator *wlk=new WlkOperator();
        wlk->SaveSampleInfo(experimentGuid);

        QSqlDatabase db = dbHelper::openConnection();
        QSqlQuery query(db);
        QString sql=QString("Delete From ExperimentInfo where Id='%1'").arg(experimentGuid);
        query.exec(sql);
        sql=QString("Delete From SampleAccessInfo where SampleGuid in (Select id From SampleInfo where ExperimentGuid='%1')").arg(experimentGuid);
        query.exec(sql);
        sql=QString("Delete From SampleInfo where ExperimentGuid='%1'").arg(experimentGuid);
        query.exec(sql);
        QMLSignal::I().emitStartExperimentStatus("3");
    }
}

Q_INVOKABLE void ExperimentInfo::onePointStartExperiment(QVariantMap expInfo)
{
    QString experimentGuid=saveExperimentInfo(expInfo);

    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql;

    db.transaction();

    QList<QString> sampleIdList;
    for(int i=0;i<12;i++){
        for(int j=0;j<8;j++){
            QString sampleId=common->GetGuid();
            sql=QString("Insert into SampleInfo values("
                        "'%1',"
                        "'%2',"
                        "'%3',"
                        "'%4',"
                        "'Sample1',"
                        "'未知',"
                        "'','%5','1','1','1','1')").arg(sampleId,experimentGuid,QString::number(i),QString::number(j),QString::number(i*8+j+1));
            query.exec(sql);
            sampleIdList.append(sampleId);
        }
    }

    db.commit();
    int wlkStatus=  saveWlkFile(experimentGuid,expInfo["ExperimentName"].toString());
    if(wlkStatus==1){
        QMLSignal::I().emitStartExperimentStatus("2");
        return;
    }
    distributeData(experimentGuid,expInfo["EquId"].toString());
}

Q_INVOKABLE QVariantMap ExperimentInfo::getExperimentInfo(QString equId)
{
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql=QString("Select ExperimentGuid From EquipmentInfo Where id='%1'").arg(equId);
    query.exec(sql);
    QString expGuid;
    while (query.next()) {
        expGuid=query.value("ExperimentGuid").toString();
    }
    sql=QString("Select AmplGuid,AmplName,ExperimentName,Code,"
                "System,ConsumableType,TestKit "
                "From ExperimentInfo e "
                "Where e.Id='%1'").arg(expGuid);
    query.exec(sql);
    QVariantMap map;
    while (query.next()) {
        for (int i = 0; i < query.record().count(); ++i) {
            map[query.record().fieldName(i)] = query.value(i);
        }
    }
    return map;
}

Q_INVOKABLE QVariantList ExperimentInfo::getSampleInfo(QString equId)
{
    QVariantList result;
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql=QString("Select ExperimentGuid From EquipmentInfo Where id='%1'").arg(equId);
    query.exec(sql);
    QString expGuid;
    while (query.next()) {
        expGuid=query.value("ExperimentGuid").toString();
    }
    sql=QString("Select ID,ColNum,RowNum,SampleName,SampleType,SampleConc,FAM,ROX,CY5,VIC "
                "From SampleInfo Where ExperimentGuid='%1'").arg(expGuid);
    query.exec(sql);
    while (query.next()) {
        QVariantMap map;
        for (int i = 0; i < query.record().count(); ++i) {
            map[query.record().fieldName(i)] = query.value(i);
        }
        result.append(map);
    }
    return  result;
}

Q_INVOKABLE void ExperimentInfo::openDoor(QString equId){
    QString finalData="62 00 00 3D 00 0A 00 03 00 01 00 00 00 00 55 AA";
    QByteArray finalInfo=common->GetSendData(finalData);
    if(clientList.contains(equId)){
        clientList[equId]->ClientSendingData(finalInfo);
    }
    else if(serialPortClientList.contains(equId))
    {
        serialPortClientList[equId]->ClientSendingData(finalInfo);
    }
}

Q_INVOKABLE void ExperimentInfo::closeDoor(QString equId){
    QString finalData="62 00 00 3D 00 0A 00 03 00 02 00 00 00 00 55 AA";
    QByteArray finalInfo=common->GetSendData(finalData);
    if(clientList.contains(equId)){
        clientList[equId]->ClientSendingData(finalInfo);
    }
    else if(serialPortClientList.contains(equId))
    {
        serialPortClientList[equId]->ClientSendingData(finalInfo);
    }
}

int ExperimentInfo::saveWlkFile(QString experimentGuid,QString fileName)
{
    QString path="/path/to/default/"+fileName;
    QString  wlkSavePath = QFileDialog::getSaveFileName(NULL, "保存", path,"Wlk files(*.wlk)");
    if(wlkSavePath.isEmpty()&&wlkSavePath.isNull()){
        return 1;
    }
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql=QString("Update ExperimentInfo Set WlkSavePath='%1' Where Id='%2'").arg(wlkSavePath,experimentGuid);
    query.exec(sql);
    return  0;
}

QString ExperimentInfo::saveExperimentInfo(QVariantMap info)
{
    QSqlDatabase db=dbHelper::openConnection();
    QSqlQuery query(db);
    QString id=common->GetGuid();
    QString runTime=common->GetDateTimeStr();

    if(info["AmplGuid"].toString()=="0"){      // 扩增程序名称从open表里获取 (jnn) ===========
        QString sql = "Select ProgramName From AmplProgramOpen";
        query.exec(sql);
        QString amplName;
        while(query.next()){
            amplName = query.value("ProgramName").toString();
        }
        sql = QString("Insert into ExperimentInfo (Id,EquId,EquName,AmplGuid,AmplName,ExperimentName,Code,System,ConsumableType,TestKit,Status) "
                      "values('%1','%2',(Select equName From equipmentInfo WHERE ID='%2'),'%3','%9','%4','%5','%6','%7','%8','未启动')").arg
                (id,info["EquId"].toString(),info["AmplGuid"].toString(),info["ExperimentName"].toString(),info["Code"].toString(),
                info["System"].toString(),info["ConsumableType"].toString(),info["TestKit"].toString(), amplName);
        query.exec(sql);
        // 扩增程序名称从open表里获取结束 (jnn) ====================================
    }else{
        QString sql=QString("Insert into ExperimentInfo (Id,EquId,EquName,AmplGuid,AmplName,ExperimentName,Code,System,ConsumableType,TestKit,Status) values('%1','%2',(Select equName From equipmentInfo WHERE ID='%2'),'%3',(Select ProgramName From AmplProgram WHERE ID='%3'),'%4','%5','%6','%7','%8','未启动')").arg
                (id,info["EquId"].toString(),info["AmplGuid"].toString(),info["ExperimentName"].toString(),info["Code"].toString(),
                info["System"].toString(),info["ConsumableType"].toString(),info["TestKit"].toString());

        query.exec(sql);
    }


    return  id;
}

int ExperimentInfo::saveSampleInfo(QVariantList sampleInfo,QString expGuid)
{
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql;

    db.transaction();

    foreach(QVariant info,sampleInfo){
        QVariantMap map=info.value<QVariantMap>();

        QString id=common->GetGuid();
        QString colNum=map.value("ColNum").toString();
        QString rowNum=map.value("RowNum").toString();
        QString sampleName=map.value("SampleName").toString();
        QString sampleType=map.value("SampleType").toString();
        QString sampleConc=map.value("SampleConc").toString();

        QString famStatus=map.value("FAM").toString();
        QString vicStatus=map.value("VIC").toString();
        QString roxStatus=map.value("ROX").toString();
        QString cy5Status=map.value("CY5").toString();

        sql=QString("Insert into SampleInfo values("
                    "'%1',"
                    "'%2',"
                    "'%3',"
                    "'%4',"
                    "'%5',"
                    "'%6',"
                    "'%7','%8','%9','%10','%11','%12')").arg(id,expGuid,colNum,rowNum,sampleName,sampleType,
                                                             sampleConc,QString::number(colNum.toDouble()*8+rowNum.toDouble()+1),famStatus,
                                                             vicStatus, roxStatus, cy5Status);
        query.exec(sql);

    }

    db.commit();
    return 0;
}

void ExperimentInfo::distributeData(QString experimentGuid,QString equId){

    LogHelperJ::write("distributeData expGuid:" + experimentGuid + " equId:" + equId);

    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql=QString("Select AmplGuid From ExperimentInfo Where Id='%1'").arg(experimentGuid);
    QString programId;
    query.exec(sql);
    while (query.next()) {
        programId=query.value("AmplGuid").toString();
    }
    if(programId=="0"){
        sql="Select * from AmplStepOpen ";
    }else{
        sql=QString("Select * from AmplStep where programId='%1' order by StepNum").arg(programId);
    }
    query.exec(sql);

    QString data="";
    int stepNum=0;
    while (query.next()) {
        QString step=common->TenToSixteen( query.value("StepNum").toInt(),2);
        QString rate=common->TenToSixteen(query.value("Rate").toInt()*100,4);
        QString temp=common->TenToSixteen( query.value("Temperature").toInt()*100,4);
        QString time=common->TenToSixteen( query.value("ExecutionTime").toInt(),4);
        QString cycleNumber=common->TenToSixteen(query.value("CycleNumber").toInt(),2);
        QString cycleNum=common->TenToSixteen( query.value("CycleNum").toInt(),2);
        QString collect=query.value("IsCollect").toString()=="是"?"01":"00";
        QString stepData=QString("%1 %2 %3 %4 %5 %6 %7 ").arg(step,temp,rate,time,cycleNumber,cycleNum,collect);

        data+=stepData;
        stepNum++;
    }
    if(programId=="0"){
        sql="Select HotCoverTemp from AmplProgramOpen ";
    }else{
        sql=QString("Select HotCoverTemp From AmplProgram Where Id=(Select AmplGuid from ExperimentInfo where id='%1')").arg(experimentGuid);
    }
    query.exec(sql);
    QString hotCoverTemp="";
    while (query.next()) {
        if(query.value("HotCoverTemp").toDouble()==0){
            hotCoverTemp="00 00";
        }else{
            hotCoverTemp=common->TenToSixteen(query.value("HotCoverTemp").toDouble()*100,4);
        }
    }

    QString finalData=QString(
                "00 00 00 01 %1 01 %4 %2 "
                "%3 55 AA").arg(common->TenToSixteen(stepNum,2),data,common->GetCrcCheck(data.toLatin1()),hotCoverTemp);

    QString dataInfo=finalData;
    QString dataLength=common->TenToSixteen( finalData.remove(QRegExp("\\s")).length()/2,4);

    QString head= QString("62 00 00 38 %1 ").arg(dataLength);

    sendResult=head+dataInfo;
    finalInfo=common->GetSendData(sendResult);

    logClient->WriteLog("CommLog",sendResult,equId);
    if(clientList.contains(equId)){
        clientList[equId]->ClientSendingData(finalInfo);
        clientList[equId]->experimentStatus=0;
        QObject::connect(clientList[equId],&TcpClient::successStart,this,&ExperimentInfo::startExperimentResult,Qt::DirectConnection);

    }
    else if(serialPortClientList.contains(equId)){
        serialPortClientList[equId]->ClientSendingData(finalInfo);
        serialPortClientList[equId]->experimentStatus=0;
        QObject::connect(serialPortClientList[equId],&SerialportClient::successStart,this,&ExperimentInfo::startExperimentResult,Qt::DirectConnection);
    }

    equGuid=equId;
    expGuid=experimentGuid;
    QEventLoop loop;
    QTimer timer;
    timer.setSingleShot(true);

    // 设置超时时间（例如5秒）
    int timeout = 3000;

    // 连接超时信号
    QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    timer.start(timeout);
    responseReceived = false;  // 用于标记是否收到响应

    // 启动事件循环，等待响应或超时
    loop.exec();

    if (!responseReceived)
    {
        QMLSignal::I().emitStartExperimentStatus("0");
        LogHelperJ::write("distributeData TimeOut");
    }
}

void ExperimentInfo::startExperimentResult(){
    responseReceived=true;
    if(clientList.contains(equGuid)){
        if(clientList[equGuid]->experimentStatus==0 && sendNum<3){
            clientList[equGuid]->ClientSendingData(finalInfo);
            clientList[equGuid]->experimentStatus=0;
            logClient->WriteLog("CommLog","发送:\n"+sendResult,equGuid);
            sendNum+=1;
        }
        if(clientList[equGuid]->experimentStatus==0 && sendNum>=3){
            LogHelperJ::write("distributeData sendNum>=3");
        }
        if(clientList[equGuid]->experimentStatus==1){
            QSqlDatabase db = dbHelper::openConnection();
            QSqlQuery query(db);
            eqptinfo eqInfo;
            QString samplesum=eqInfo.sampelsumread();
            QString sql="Select count(Distinct s.Id) as Sums from sampleInfo s "
                        "Join SampleAccessInfo a on s.Id=a.SampleGuid ";
            query.exec(sql);
            while (query.next()) {
                eqInfo.sampelsumwrite(QString::number(samplesum.toDouble()+query.value("Sums").toDouble()));
            }

            QString beginTime = common->GetDateTimeStr();
            sql= QString("Update ExperimentInfo set Status='运行',RunTime='%2' where id='%1'").arg(expGuid,beginTime);
            query.exec(sql);
            sql= QString("Update EquipmentInfo set EquStatus='2',ExperimentGuid='%1' where id='%2'").arg(expGuid,equGuid);
            bool res = query.exec(sql);
            LogHelperJ::write(sql + (res?"[true]":"[false]"));

            QString amplGuid;
            sql=QString("Select AmplGuid From ExperimentInfo Where id='%1' ").arg(expGuid);
            query.exec(sql);
            while (query.next()) {
                amplGuid=query.value("AmplGuid").toString();
            }
            if(amplGuid=="0"){
                sql=QString("Insert into AmplProgramPro Select '%1',* From AmplProgramOpen").arg(expGuid);

            }else {
                sql=QString("Insert into AmplProgramPro Select '%1',* From AmplProgram Where Id='%2'").arg(expGuid,amplGuid);
            }
            query.exec(sql);

            if(amplGuid=="0"){
                sql=QString("Insert into AmplStepPro Select '%1',* From AmplStepOpen ").arg(expGuid);

            }else {
                sql=QString("Insert into AmplStepPro Select '%1',* From AmplStep Where ProgramId='%2'").arg(expGuid,amplGuid);
            }
            query.exec(sql);

            clientList[equGuid]->tempOrder=0;
            clientList[equGuid]->experimentGuid=expGuid;
            tempThread = new GetTempThread();
            connect(this,&ExperimentInfo::startTempThread,tempThread,&GetTempThread::run);

            tempThread->equGuid=equGuid;
            emit startTempThread();
            QObject::disconnect(clientList[equGuid],&TcpClient::successStart,this,&ExperimentInfo::startExperimentResult);
            QMLSignal::I().emitStartExperimentStatus("1");

            LogHelperJ::write("distributeData Succeed");
        }

    }
    else if(serialPortClientList.contains(equGuid)){
        if(serialPortClientList[equGuid]->experimentStatus==0 && sendNum<3){
            serialPortClientList[equGuid]->ClientSendingData(finalInfo);
            serialPortClientList[equGuid]->experimentStatus=0;
            logClient->WriteLog("CommLog","发送:\n"+sendResult,equGuid);
            sendNum+=1;
        }
        if(serialPortClientList[equGuid]->experimentStatus==0 && sendNum>=3){
            LogHelperJ::write("distributeData sendNum>=3");
        }
        if(serialPortClientList[equGuid]->experimentStatus==1){
            QSqlDatabase db = dbHelper::openConnection();
            QSqlQuery query(db);
            eqptinfo eqInfo;
            QString samplesum=eqInfo.sampelsumread();
            QString sql="Select count(Distinct s.Id) as Sums from sampleInfo s "
                        "Join SampleAccessInfo a on s.Id=a.SampleGuid ";
            query.exec(sql);
            while (query.next()) {
                eqInfo.sampelsumwrite(QString::number(samplesum.toDouble()+query.value("Sums").toDouble()));
            }

            QString beginTime = common->GetDateTimeStr();
            sql= QString("Update ExperimentInfo set Status='运行',RunTime='%2' where id='%1'").arg(expGuid,beginTime);
            query.exec(sql);
            sql= QString("Update EquipmentInfo set EquStatus='2',ExperimentGuid='%1' where id='%2'").arg(expGuid,equGuid);
            bool res = query.exec(sql);
            LogHelperJ::write(sql + (res?"[true]":"[false]"));

            QString amplGuid;
            sql=QString("Select AmplGuid From ExperimentInfo Where id='%1' ").arg(expGuid);
            query.exec(sql);
            while (query.next()) {
                amplGuid=query.value("AmplGuid").toString();
            }
            if(amplGuid=="0"){
                sql=QString("Insert into AmplProgramPro Select '%1',* From AmplProgramOpen").arg(expGuid);

            }else {
                sql=QString("Insert into AmplProgramPro Select '%1',* From AmplProgram Where Id='%2'").arg(expGuid,amplGuid);
            }
            query.exec(sql);

            if(amplGuid=="0"){
                sql=QString("Insert into AmplStepPro Select '%1',* From AmplStepOpen ").arg(expGuid);

            }else {
                sql=QString("Insert into AmplStepPro Select '%1',* From AmplStep Where ProgramId='%2'").arg(expGuid,amplGuid);
            }
            query.exec(sql);

            serialPortClientList[equGuid]->tempOrder=0;
            serialPortClientList[equGuid]->experimentGuid=expGuid;
            tempThread = new GetTempThread();
            connect(this,&ExperimentInfo::startTempThread,tempThread,&GetTempThread::run);

            tempThread->equGuid=equGuid;
            emit startTempThread();
            QObject::disconnect(serialPortClientList[equGuid],&SerialportClient::successStart,this,&ExperimentInfo::startExperimentResult);
            QMLSignal::I().emitStartExperimentStatus("1");

            LogHelperJ::write("distributeData Succeed");
        }

    }

}

//样本名获取
QStringList ExperimentInfo::selsamplename(){
    QStringList alldata;
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql="Select Name From ItemCode Where DicCode=1 and IsDefault = '1' ";
    query.exec(sql);
    while (query.next()) {
        alldata.append(query.value("Name").toString());
    }
    sql="Select Name From ItemCode Where DicCode=1 and IsDefault = '0' ";
    query.exec(sql);
    while (query.next()) {
        alldata.append(query.value("Name").toString());
    }
    return alldata;
}

//样本类型获取
QStringList ExperimentInfo::selsampletype(){
    QStringList alldata;
    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);
    QString sql="Select Name From ItemCode Where DicCode=2 and IsDefault = '1' ";
    query.exec(sql);
    while (query.next()) {
        alldata.append(query.value("Name").toString());
    }
    sql="Select Name From ItemCode Where DicCode=2 and IsDefault = '0' ";
    query.exec(sql);
    while (query.next()) {
        alldata.append(query.value("Name").toString());
    }
    return alldata;
}

// 样本导入
QVariantList ExperimentInfo::samplein()
{
    QVariantList alldata;
    for(int i = 0; i < 96; i ++){
        QStringList val({"","",""});
        alldata.push_back(val);
    }
    QString pathin = QFileDialog::getOpenFileName(nullptr, tr("Open Excel file"), "", tr("Excel Files (*.xlsx *.xls)"));

    if(pathin==""){
        alldata[0] = "2";
        return alldata;
    }

    QXlsx::Document xlsx(pathin);
    QStringList sheetnames =xlsx.sheetNames();
    xlsx.selectSheet("工作表1");

    if(xlsx.read(2, 1).toString()!="序号" || xlsx.read(2, 2).toString()!="孔位" || xlsx.read(2, 3).toString()!="样本名称" || xlsx.read(2, 4).toString()!="样本类型" ||xlsx.read(2, 5).toString()!="浓度"){
        alldata[0] = "1";
        return alldata;
    }

    for(int i=3;i<=98;i++){
        QString posi = xlsx.read(i, 2).toString();
        int     posiId = 0;
        if(posi.size()==2){
            int a = posi[0].unicode()-'A';
            int b = posi[1].unicode()-'1';
            posiId = a*12 + b;
            if(posiId < 0 || posiId >= 96){
                continue;
            }
            QStringList rowval;
            for(int j=3;j<6;j++){
                rowval.append(xlsx.read(i,j).toString());
            }
            alldata[posiId] = rowval;
        }
        else if(posi.size()==3){
            int a = posi[0].unicode()-'A';
            int b = 10 + posi[2].unicode()-'1';
            posiId = a*12 + b;
            if(posiId < 0 || posiId >= 96){
                continue;
            }
            QStringList rowval;
            for(int j=3;j<6;j++){
                rowval.append(xlsx.read(i,j).toString());
            }
            alldata[posiId] = rowval;
        }
    }
    return alldata;
}


